package com.miracle.framework.remote.netty.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.miracle.framework.remote.client.Client;
import com.miracle.framework.remote.client.exception.ClientCloseException;
import com.miracle.framework.remote.client.exception.ClientException;
import com.miracle.framework.remote.exchange.Request;
import com.miracle.framework.remote.exchange.Response;
import com.miracle.framework.remote.netty.codec.SerializeType;
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class NettyClient implements Client , ApplicationContextAware {
private ApplicationContext applicationContext;
@Value("${client.worker.group.threads}")
private int workerGroupThreads;
@Value("${serialize.type}")
private SerializeType serializeType;
private EventLoopGroup workerGroup;
private Channel channel;
@Override
public void connect(final InetSocketAddress socketAddress) {
workerGroup = new NioEventLoopGroup(workerGroupThreads);
Bootstrap bootstrap = new Bootstrap();
bootstrap
.group(workerGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
.handler(applicationContext.getBean(serializeType.getClientChannelInitializer()));
channel = bootstrap.connect(socketAddress.getAddress().getHostAddress(), socketAddress.getPort()).syncUninterruptibly().channel();
}
@Override
public Response sent(final Request request) {
channel.writeAndFlush(request);
return applicationContext.getBean(serializeType.getClientChannelInitializer()).getResponse(request.getMessageId());
}
@Override
public InetSocketAddress getRemoteAddress() {
SocketAddress remoteAddress = channel.remoteAddress();
if (!(remoteAddress instanceof InetSocketAddress)) {
throw new ClientException(new RuntimeException("Get remote address error, should be InetSocketAddress"));
}
return (InetSocketAddress) remoteAddress;
}
@Override
public void close() {
if (null == channel) {
throw new ClientCloseException();
}
workerGroup.shutdownGracefully();
channel.closeFuture().syncUninterruptibly();
workerGroup = null;
channel = null;
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}